import math
from Source.CWJ import qyhf
from Methods.tools import *
from secondary_main import pipelist_main, double_update

#含三通水管排管算法
def Tee_sorting(pipeBase, blockBase, block_arr, PipeGroup_info, new_allpipelist, flag = 0):
    PipeGroupNo = PipeGroup_info[0]
    PipeGroup_Type = PipeGroup_info[1]
    ceilling = PipeGroup_info[2]

#如果是竖直三通实体水管，则返回原管道
    if vertical_tee(pipeBase, PipeGroupNo,PipeGroup_Type):
        print('当前管道组为含三通竖直水管,退出三通算法，返回原管道')
        for PipeGroup in pipeBase._pipeGroups:
            if PipeGroup.pipeGroupNo == PipeGroupNo:
                for pipeList in PipeGroup._pipeLists:
                    plist = []
                    for pipe in pipeList._pipes:
                        a = [pipe.start,pipe.end,pipe.size.width,pipe.size.height,pipe.angle]
                        plist.append(a)
                    new_allpipelist.append(plist)
        # 把所有生成新管道都添加到障碍物列表中,以便之后的管道组遇到三通会避障
        PipeGroup_length = len(pipeBase._pipeGroups[PipeGroupNo - 1]._pipeLists)
        for i in range(len(new_allpipelist) - PipeGroup_length, len(new_allpipelist)):
            new_blocklist = qyhf.pipes_to_blocks(new_allpipelist[i], 10)
            # # 管道类型的障碍物，添加到障碍物对象中
            add(new_blocklist, blockBase)
            # # 管道类型的障碍物，添加到障碍物数组中
            block_arr.extend(new_blocklist)
        return


    for PipeGroup in pipeBase._pipeGroups:
        if PipeGroup.pipeGroupNo == PipeGroupNo:
            double_point,single_point,zero_point  = PipeGroup.getTeeType()
            break
    while double_point !=[]:#持续遍历“双”栈，只要“双”栈中不为空，则不跳出循环
        double = double_point.pop()#“双”栈中弹出一个“双”
        Lists = double.lists#当前三通的三段标号,list类型,即[1,3,2]
        common_label,Tee_object = Tee_judge(Lists, zero_point, single_point, double_point)#判断是否命中三通

        if(common_label == None):#如果返回的E列标号为None，说明该三通的E列没有命中下一个三通,遇到了终点,排管结束

            #寻找终点E管道
            endlist = find_endlist(pipeBase,PipeGroupNo)

            #获取两个S列对应的管道信息
            all_height = []
            a =[]
            plist_sort = []
            for k in Lists:
                if k!=endlist:
                    a.append(k)
                    plist_sort.append(PipeListNo_to_PipeList(PipeGroupNo, k, pipeBase))
            plist_sort[0], plist_sort[1] = list_2_S_reverse(plist_sort[0], plist_sort[1])
            b = [plist_sort[0][-1][1][0],plist_sort[0][-1][1][1]]#记录一个S列管道最后一段的终点坐标,用于后面终点列E坐标判断,这里用的是[x,y]坐标，因为Z坐标会改变

            #排两列S管道
            for i in range(0,2):
                plist = plist_sort[i]
                print('------------------正在排第', a[i], '号管道-----------------------')
                change_flag, slope_change_flag, new_pipeList, position_list = pipelist_main(flag, plist, block_arr, blockBase, PipeGroup_Type, ceilling, pipeBase)#排管
                double_update(new_pipeList, pipeBase, PipeGroupNo,  a[i], position_list, change_flag, slope_change_flag) #将管道数组信息更新至管道类及添加连接关系
                all_height.append(new_pipeList[len(new_pipeList)-1][1][2])#记录新管道的终点高度
                new_allpipelist.append(new_pipeList)
            change_end_height(new_allpipelist, min(all_height))  # 将两列S管道的终点坐标改为最低高度

            #排E列管道
            print('------------------正在排第', endlist, '号管道-----------------------')
            plist = PipeListNo_to_PipeList(PipeGroupNo, endlist, pipeBase)
            if coincide_judge(b,plist[0][0],400) == False:
                plist = pipelist_reverse(plist)

            change_height(plist, min(all_height))#改变E列管道高度
            change_flag, slope_change_flag, new_pipeList, position_list = pipelist_main(flag, plist, block_arr, blockBase, PipeGroup_Type, ceilling, pipeBase)  # 排管
            double_update(new_pipeList, pipeBase, PipeGroupNo, endlist, position_list, change_flag, slope_change_flag) #将管道数组信息更新至管道类及添加连接关系
            new_allpipelist.append(new_pipeList)

        else:#否则,说明命中了三通,管道列下标[E,S,S]
            labels = find_labels(common_label)
            Tee_upgrade(Tee_object, zero_point, single_point, double_point)#三通升级

            all_height = []
            a =[]
            plist_sort = []
            for i in range(1,3):
                a.append(Lists[labels[i]])
                plist_sort.append(PipeListNo_to_PipeList(PipeGroupNo,Lists[labels[i]],pipeBase))
            plist_sort[0], plist_sort[1] = list_2_S_reverse(plist_sort[0], plist_sort[1])#纠正两列S的坐标,即保证他们的终点坐标一致
            b = [plist_sort[0][-1][1][0], plist_sort[0][-1][1][1]]  # 记录一个S列管道最后一段的终点坐标,用于后面终点列E坐标判断,这里用的是[x,y]坐标，因为Z坐标会改变

            #排两列S管道
            for i in range(0, 2):
                plist = plist_sort[i]
                print('------------------正在排第', a[i], '号管道-----------------------')
                change_flag, slope_change_flag, new_pipeList, position_list = pipelist_main(flag, plist, block_arr, blockBase, PipeGroup_Type, ceilling, pipeBase)#排管
                double_update(new_pipeList, pipeBase, PipeGroupNo, a[i], position_list, change_flag, slope_change_flag) #将管道数组信息更新至管道类及添加连接关系
                all_height.append(new_pipeList[len(new_pipeList)-1][1][2])#记录新管道的终点高度
                new_allpipelist.append(new_pipeList)
            change_end_height(new_allpipelist, min(all_height))  # 将两列S管道的终点坐标改为最低高度

            plist = PipeListNo_to_PipeList(PipeGroupNo,Lists[labels[0]],pipeBase)

            if coincide_judge(b, plist[0][0], 300) == False:
                pipelist_pipebase_reverse(PipeGroupNo, Lists[labels[0]], pipeBase)

            # 改变E列管道高度,这里改变的是pipebase
            pipeBase = change_pipebase_height(Lists[labels[0]] ,PipeGroupNo,pipeBase,min(all_height))

    # 排完所有三通管道后,把所有生成新管道都添加到障碍物列表中,以便之后的管道组遇到三通会避障
    PipeGroup_length = len(pipeBase._pipeGroups[PipeGroupNo-1]._pipeLists)
    for i in range(len(new_allpipelist)-PipeGroup_length, len(new_allpipelist)):
        new_blocklist = qyhf.pipes_to_blocks(new_allpipelist[i], 10)
        # # 管道类型的障碍物，添加到障碍物对象中
        add(new_blocklist, blockBase)
        # # 管道类型的障碍物，添加到障碍物数组中
        block_arr.extend(new_blocklist)


#输入当前三通标号，判断是否命中三通，如果命中，则返回E列下标，和命中的三通对象，否则返回None
def Tee_judge(Lists,zero_point,single_point,double_point):
    common_label = None
    Tee_object = None
    for i in range(3):
        for zero in zero_point:
            zero_Lists = zero.lists
            for j in zero_Lists:
                if Lists[i] == j:
                    common_label = i
                    Tee_object = zero
                    break
        for single in single_point:
            single_Lists = single.lists
            for j in single_Lists:
                if Lists[i] == j:
                    common_label = i
                    Tee_object = single
                    break
        for double in double_point:
            double_Lists = double.lists
            for j in double_Lists:
                if Lists[i] == j:
                    common_label = i
                    Tee_object = double
                    break
    return common_label,Tee_object

#输入命中列下标，返回管道列下标[E,S,S]
def find_labels(common_label):
    Independent_label = []
    for i in range(3):
        if i != common_label:
            Independent_label.append(i)
    return [common_label,Independent_label[0],Independent_label[1]]

#三通升级函数,输入待升级的对象,返回升级后的栈
def Tee_upgrade(Tee_object,zero_point,single_point,double_point):
    if Tee_object in zero_point:
        zero_point.remove(Tee_object)
        single_point.append(Tee_object)
    elif Tee_object in single_point:
        single_point.remove(Tee_object)
        double_point.append(Tee_object)
    else:
        print('三通升级函数出错,返回原栈！')
        
#输入pipebase,PipeGroupNo寻找终点列标号
def find_endlist(pipeBase,PipeGroupNo):
    endlist = -1
    for PipeGroup in pipeBase._pipeGroups:
        if PipeGroup.pipeGroupNo == PipeGroupNo:
            for PipeList in PipeGroup._pipeLists:
                if PipeList.mark == 'E':
                    endlist = PipeList.pipeListNo
                else:
                    continue
    if endlist == -1:
        print('寻找终点列坐标出错，返回值为-1')
    return endlist

#由管道列标号,返回该列管道数组
def PipeListNo_to_PipeList(PipeGroupNo,PipeListNo,pipeBase):
    a = []
    for PipeGroup in pipeBase._pipeGroups:
        if PipeGroup.pipeGroupNo == PipeGroupNo:
            for pipeList in PipeGroup._pipeLists:
                if pipeList.pipeListNo == PipeListNo:
                    for pipe in pipeList._pipes:
                        a.append([pipe.start, pipe.end, pipe.size.width, pipe.size.height, pipe.angle])
    return a

#由管道组标号,返回该组管道数组
def PipeGroupNo_to_PipeGroup(PipeGroupNo, pipeBase): 
    a = []
    for PipeGroup in pipeBase._pipeGroups:
        if PipeGroup.pipeGroupNo == PipeGroupNo:
            for i in range(len(PipeGroup._pipeLists)):
                a.append(PipeListNo_to_PipeList(PipeGroupNo,i+1,pipeBase))
    return a

#改变E列start和end高度,数组中改正,直接排管
def change_height(pipelist,height):
    for pipe in pipelist:
        pipe[0][2]=height
        pipe[1][2]=height
        
#改变两个S列管道end的高度
def change_end_height(new_allpipelist,height):
    length_1 = len(new_allpipelist[-1])#最后一列管道的长度
    length_2 = len(new_allpipelist[-2])
    new_allpipelist[-1][length_1-1][1][2] = height
    new_allpipelist[-2][length_2 - 1][1][2] = height

#判断两段管是否离得很近,利用[x,y]来判断,这里是输入为长度为3的数组,即[x,y,z]
def coincide_judge(pipe1,pipe2,length):         #b [97085.935429135, 187899.566136903]
            #[97389.935429135, 187899.566136903, 55473.4]
    if math.sqrt((pipe1[0]-pipe2[0])**2+(pipe1[1]-pipe2[1])**2) < length:
        return True
    else:
        return False

#改变对象中管道列的高度
def change_pipebase_height(PipeListNo,PipeGroupNo,pipeBase,height):
    for PipeGroup in pipeBase._pipeGroups:
        if PipeGroup.pipeGroupNo == PipeGroupNo:
            for PipeList in PipeGroup._pipeLists:
                if PipeList.pipeListNo == PipeListNo:
                    for Pipe in PipeList._pipes:
                        Pipe.start[2] = height
                        Pipe.end[2] = height
    return pipeBase

#将一列坐标的起点和终点互换
def pipelist_reverse(plist):
    length = len(plist)
    for i in plist:
        temp = i[0]
        i[0] = i[1]
        i[1] = temp
    a = []
    for j in range(length-1,-1,-1):
        a.append(plist[j])
    return a

#将对象中某列的起点终点坐标互换
def pipelist_pipebase_reverse(PipeGroupNo,PipeListNo,pipeBase):
    for PipeGroup in pipeBase._pipeGroups:
        if PipeGroup.pipeGroupNo == PipeGroupNo:
            for PipeList in PipeGroup._pipeLists:
                # print(PipeList)
                if PipeList.pipeListNo == PipeListNo:
                    # print(PipeList)
                    for pipe in PipeList._pipes:
                        # print(pipe)
                        temp = pipe.start
                        pipe.start = pipe.end
                        pipe.end = temp
                    PipeList._pipes.reverse()


#纠正两列S管道的起点和终点坐标
def list_2_S_reverse(plist1,plist2):
    if coincide_judge(plist1[-1][1], plist2[-1][1], 300) == True:#如果两管道终点坐标靠近,则返回原管道,这里比较的是终点坐标的x，y
    # if [plist1[-1][1][0],plist1[-1][1][1]] == [plist2[-1][1][0],plist2[-1][1][1]]:#如果两管道终点坐标相等,则返回原管道,这里比较的是终点坐标的x，y
        return plist1,plist2
    else:
        plist1 = pipelist_reverse(plist1)#否则把plist1 S和E 坐标互换再比较
        if coincide_judge(plist1[-1][1], plist2[-1][1], 300) == True:
            return plist1, plist2
        else:
            plist1 = pipelist_reverse(plist1)#否则把plist2 S和E 坐标互换再比较
            plist2 = pipelist_reverse(plist2)
            if coincide_judge(plist1[-1][1], plist2[-1][1], 300) == True:
                return plist1, plist2
            else:
                plist1 = pipelist_reverse(plist1)#否则把plist2,plist2 S和E 坐标互换再比较
                if coincide_judge(plist1[-1][1], plist2[-1][1], 300) == True:
                    return plist1, plist2
                else:
                    plist1 = pipelist_reverse(plist1)
                    plist2 = pipelist_reverse(plist2)
                    print('互换坐标函数出错，返回原管道')
                    return plist1, plist2

# 判断含三通的组，id是否发生改变，如果任一段管道发生改变，则返回True，输入的是PipeGroup类
def judge_tee_fitting(PipeGroup):
    for pipeList in PipeGroup._pipeLists:
        for Pipe in pipeList._pipes:
            if len(Pipe.uid) < 30:
                return True
            else:
                continue
    return False

# 三通fitting函数，决定三通fitting的保留或者autoconnect功能，传入的信息为pipeBase
def tee_fitting(pipeBase,pipeBase_copy):
    for PipeGroup in pipeBase._pipeGroups:
        #先判断该组是否含有三通
        if PipeGroup._teeList != []:
            # 如果是点线管，则全部autoconnect
            if (PipeGroup.type =='LineDuct') or (PipeGroup.type =='LinePipe'):
                for tee in PipeGroup._teeList:
                    connector = []
                    sub_connector = []
                    for tee_ListNo in tee.lists:
                        for pipeList in PipeGroup._pipeLists:
                            if pipeList.pipeListNo == tee_ListNo:
                                if pipeList.mark == 'E':
                                    sub_connector.append(pipeList._pipes[0].uid)
                                else:
                                    sub_connector.append(pipeList._pipes[-1].uid)
                    connector.append(sub_connector)
                    connector.append(tee.familyName)
                    connector.append(tee.symbolName)
                    PipeGroup.connectors.append(connector)
            # 如果是实体管，则需要autoconnect和读取输入fitting功能
            else:
                # 此为id发生改变的情况，需要autoconnect，并改变对应三通的id
                if judge_tee_fitting(PipeGroup):
                    for tee in PipeGroup._teeList:
                        tee.uid = "S-" + tee.uid
                        connector = []
                        sub_connector = []
                        for tee_ListNo in tee.lists:
                            for pipeList in PipeGroup._pipeLists:
                                if pipeList.pipeListNo == tee_ListNo:
                                    if pipeList.mark == 'E':
                                        sub_connector.append(pipeList._pipes[0].uid)
                                    else:
                                        sub_connector.append(pipeList._pipes[-1].uid)
                        connector.append(sub_connector)
                        connector.append('Default')
                        connector.append('Default')
                        PipeGroup.connectors.append(connector)
                                #此为id未发生改变的情况，照抄fitting，需要把所有坐标恢复成原来的形式
                else:
                    # print(pipeBase_copy._pipeGroups[0]._pipeLists[1]._pipes[0].start)
                    # print(pipeBase_copy._pipeGroups[0]._pipeLists[1]._pipes[0].end)
                    for PipeGroup1 in pipeBase_copy._pipeGroups:
                        if PipeGroup1.pipeGroupNo == PipeGroup.pipeGroupNo:
                            pipeBase._pipeGroups = [PipeGroup1 if i ==PipeGroup else i for i in pipeBase._pipeGroups ]
                            break
    # return pipeBase
#判断是否含竖直三通的函数
def vertical_tee(pipeBase,PipeGroupNo,PipeGroup_Type):
    if PipeGroup_Type == 'Pipe':
        for PipeGroup in pipeBase._pipeGroups:
            if PipeGroup.pipeGroupNo == PipeGroupNo:
                for pipeList in PipeGroup._pipeLists:
                    for pipe in pipeList._pipes:
                        # print(pipe.start[0:2], pipe.end[0:2])
                        if coincide_judge(pipe.start,pipe.end,10):#判断x，y坐标是否重合
                            return True
    return False
